﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using AIthin.Neuro;
using AIthin.Model;

namespace AIthin.Model.Body
{
    public class Wurm
    {
        /// <summary>
        /// input Matrix für NN
        /// </summary>
        short[,] input;
        /// <summary>
        /// output vektor von NN
        /// </summary>
        short[] output;
        public Reality reality;
        public INetwork mind;
        public Actuator muscle;
        public Retina retina;
        public Layer layerPosition;

        public bool Dead = false;
        public bool isHitted = false;
        int actuatorNeurons = 8;
        int attentionUpNeuron;
        int attentionDownNeuron;
        int attentionLeftNeuron;
        int attentionRightNeuron;
        int[] moveLeftNeuron;
        int[] moveRightNeuron;
        int countPositionNeurons = 256;
        int[] musclePositionNeurons;
        int[] musclePositionSignals;

        public int damageCapacity { get; protected set; }

        public Wurm(INetwork m, Reality r)
        {
            reality = r;
            mind = m;

            muscle = new Actuator(this);
            retina = new Retina(32, this);

            actuatorNeurons = (m.outputsCount - 6) / 2;

            moveLeftNeuron = new int[actuatorNeurons];
            moveRightNeuron = new int[actuatorNeurons];

            attentionUpNeuron = mind.NeuronsCount - 1;
            attentionDownNeuron = mind.NeuronsCount - 2;
            attentionLeftNeuron = mind.NeuronsCount - 3;
            attentionRightNeuron = mind.NeuronsCount - 4;

            for (int i = 0; i < actuatorNeurons; i++)
                moveLeftNeuron[i] = mind.NeuronsCount - 5 - i;

            for (int i = 0; i < actuatorNeurons; i++)
                moveRightNeuron[i] = mind.NeuronsCount - 5 - actuatorNeurons - i;

            mind.groupNeuronsAt(moveLeftNeuron, 10f, 15f, 30f, 5f, 5f);
            mind.groupNeuronsAt(moveRightNeuron, 20f, 15f, 30f, 5f, 5f);

            musclePositionNeurons = new int[countPositionNeurons];
            musclePositionSignals = new int[countPositionNeurons];

            layerPosition = new Layer((Network)mind, 40f, 15f, 0f, 2f, 30f, countPositionNeurons);

            layerPosition.connectOutputsTo(mind.layers[mind.layers.Count - 3]);

            musclePositionNeurons = layerPosition.layerNeurons.ToArray();

            mind.SetInputSignal(musclePositionNeurons, musclePositionSignals);

            damageCapacity = 100;
        }

        public void Reaction(ref Bitmap bmRealitySnap)
        {

            isHitted = false;

            Graphics g = Graphics.FromImage(bmRealitySnap);

            muscle.Draw(g);
            retina.Draw(g);

            SetPositionSignals();
           
            input = retina.ReadBitmap(bmRealitySnap);
            //prozessing signal für NN
            mind.Tick(ref input, ref musclePositionNeurons, ref musclePositionSignals);

            //wurm moving
            int muscleShift = 0;
            for (int i = 0; i < actuatorNeurons; i++)
                if (mind[moveRightNeuron[i]].Activated) muscleShift++;

            for (int i = 0; i < actuatorNeurons; i++)
                if (mind[moveLeftNeuron[i]].Activated) muscleShift--;

            muscle.move(muscleShift);
            retina.setPosition(muscle.Position-(retina.Size - muscle.Length)/2);

        }
        public void Reaction(ref short[,] inp)
        {

            //          Graphics g = Graphics.FromImage(bmRealitySnap);

            //          input = retina.ReadBitmap(bmRealitySnap);


            //            retina.Draw(g);

            //           output = new short[mind.outputsCount];

            //prozessing signal für NN
            mind.Tick(ref inp, ref musclePositionNeurons, ref musclePositionSignals);

            //wurm moving
            //          if (mind[moveLeftNeuron].Activated) muscle.links();
            //          if (mind[moveRightNeuron].Activated) muscle.rechts();

            //retina center
            /*            if (mind[attentionUpNeuron].Activated) retina.up_down(5,  bmRealitySnap.Height);
                        if (mind[attentionDownNeuron].Activated) retina.up_down(-5, bmRealitySnap.Height);
                        if (mind[attentionLeftNeuron].Activated) retina.left_right(-5, bmRealitySnap.Height);
                        if (mind[attentionRightNeuron].Activated) retina.left_right(5, bmRealitySnap.Height);
            */
            //            muscle.Draw(g);
        }
        
        /// <summary>
        /// Analysed dead or not dead
        /// </summary>
        /// <returns>true - is dead, false - isn´t dead</returns>
        public bool IsHit()
        {

            muscle.middle();
            retina.middle();

            if (--damageCapacity > 0)
            {
                return false;
            }
            else
            {
                Dead = true;
                return true;
            }
        }
        public bool checkHit()
        {
            int n = 0;
            for (int i = 8; i < 25; i++)
                if(input[i,2] == 1) n++;

            if (n == 9)
                return true;
            else
                return false;
        }

        public void SetPositionSignals()
        {
            for (int i = 2; i < muscle.LengthMaximum-1; i++ )
            {
                if (i == muscle.Position)
                {
                    musclePositionSignals[i-1] = 1;
                    musclePositionSignals[i] = 1;
                    musclePositionSignals[i + 1] = 1;
                    musclePositionSignals[2 * i - 1] = 1;
                    musclePositionSignals[2*i] = 1;
                    musclePositionSignals[2 * i +1] = 1;
                }

                else
                    musclePositionSignals[i] = 0;
            }

        }
    }
}
